跳到主要内容

JavaScript基本语法

前置知识

MDN文档 JavaScript的手册方面

  • <script> 是双标签,必须带上 </script>,如果使用自闭合会无法生效
  • 一般 JS 代码放在最下面
  • 使用 ES6 的代码可能需要使用到 Babel 将 ES6 版本的代码转换为向后兼容的 JavaScript 语法(不过这里尽量不讲 ES6 的语法,ES6 单独抽离出了几篇文章)

加上下面这句开启严格模式 必须写在第一行

"use strict";

如果 'use strict' 放在 JS 文件首行,则整个 JS 文件都将以严格模式运行;(如果该句不在首行,则无效);需要特别注意多个文件合并成一个文件的情况,此情况下,提供一个方法,每个文件使用匿名函数自执行,将 'use strict' 放在函数第一行,表示整个函数为严格模式,函数以外在为正常模式;

定义变量

JavaScript 是一门弱类型语言

var num = 10;

ES6 添加了如下两种类型用来声明变量

const 用来声明常量 let 只在所在的代码块内有效

var 和 let 的区别

var:变量提升(无论声明在何处,都会被提至其所在作用域的顶部) let:无变量提升(未到 let 声明时,是无法访问该变量的)所以局部变量都尽量使用 let 去定义

作用域

如果两个函数使用了相同的变量名,只要在函数内部就不冲突

function aaa() {
let x = 10;
}
function bbb() {
let x = 20;
}


// 内部函数可以访问外部函数
function aaa() {
let x = 10;
let c = function bbb() {
let y = x;
y++;
return y;
}
console.log(c());
}

内部变量与外部变量重名,优先使用内部变量

全局变量

默认所有的全局变量都会自动绑定在 window 对象下,这个 window 对象就代表浏览器;例如这个 alert 本身也是 window 的一个变量

let x = 100;
window.alert(x);

//可以直接把这个函数传给一个对象
let new_alert = window.alert;
new_alert(x);

//甚至可以直接重写方法
window.alert = function(){

};

综上,由于全局变量都会绑定到 window上,所以为了避免冲突,使用以下规范

  • 把自己的代码全部放在自己定义的命名空间中
  • 一般用大写表示常量(虽然有 const 关键字,但是因为是引用类型所以对象的属性可以被修改,就像 Java 的 final 关键字一样)
"use strict";
// 唯一全局变量
const alsritter = {}
// 定义全局变量
alsritter.NAME = 'alsritter'
alsritter.GENDER = 'male'
alsritter.add = function (a,b) {
console.log(a + "hello JavaScript!" + b)
}

//使用
alsritter.add('张三','李四')

比较运算符

=
== //等于(类型不同也会相等 例如数字与字符串 9 "9" )
=== //绝对等于(类型一样,值一样 一般用这个)
//NaN与所有数值都不相等,包括自己(所以只能通过 isNaN 这个函数比较)

//尽量避免使用浮点数进行运算,存在精度问题
//如果要比较最好加上使用绝对值
Math.abs(1/3 - (1 - 2/3)) < 0.00001

nullundefined 一个是空,一个是未定义,当定义了一个变量而未使用过则是 null,从未使用过且是通过 变量提升 创建的对象则是 undefined

流程控制

if 判断

let a = 100;
if (a<20){
console.log("小于20");
}else if(a<50){
console.log("小于50");
}else {
console.log("其他");
}

switch

//生成从minNum到maxNum的随机数
function randomNum(minNum, maxNum) {
switch (arguments.length) {
case 1:
return parseInt(Math.random() * minNum + 1, 10);
break;
case 2:
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
break;
default:
return 0;
break;
}
}

while 循环

while(age < 100){
age = age + 1;
console.log(age);
}

for 循环

for(let i = 0; i<100; i++){
console.log(i);
}

数组循环

const arr = [1, 2, 3, 4, 5];
arr.forEach(((value, index) => {
console.log(value +' '+ index);
}));

// 或采用传统的forEach(注意arrKey是下标)
for (let arrKey in arr) {
console.log(arr[arrKey]);
}

//ES6新出了一个遍历关键字(of)直接可以访问值
for (let number of arr) {
console.log(number)
}

数据类型

typeof 123
"number"
typeof 's'
"string"
typeof true
"boolean"
typeof NaN
"number"
typeof []
"object"
typeof {}
"object"
typeof Math.abs
"function"
typeof undefined
"undefined"

Number 类型

JS 不区分小数和整数

123 //整数
123.1 //浮点数
1.123e3 //科学计数法
-99 //复数
NaN // not a number NaN与所有数值都不相等,包括自己(所以只能通过 isNaN 这个函数比较)
Infinity //表示无限大

生成随机数

Math.ceil();  //向上取整。
Math.floor(); //向下取整。
Math.round(); //四舍五入。
Math.random(); //0.0 ~ 1.0 之间的一个伪随机数。【包含0不包含1】 //比如0.8647578968666494
Math.ceil(Math.random()*10); // 获取从 1 到 10 的随机整数 ,取0的概率极小。
Math.round(Math.random()); //可均衡获取 0 到 1 的随机整数。
Math.floor(Math.random()*10); //可均衡获取 0 到 9 的随机整数。
Math.round(Math.random()*10); //基本均衡获取 0 到 10 的随机整数,其中获取最小值 0 和最大值 10 的几率少一半。

生成[n,m]的随机整数

//生成从 minNum 到 maxNum 的随机数
function randomNum(minNum, maxNum) {
switch (arguments.length) {
case 1:
return parseInt(Math.random() * minNum + 1, 10);
break;
case 2:
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
break;
default:
return 0;
break;
}
}

字符串 String

正常字符串使用单引号或双引号包裹(注意转移字符 \n \t \' \uxxx(Unicode字符))

模板字符串(ES6里的新特性)

let name = 'alsritter';
let msg = `你好${name}`

常用的字符串方法

let name = 'alsritter';
console.log(name[0]);
console.log(name.length);

//大小写转换
// toLowerCase 转换成小写
// toUpperCase 转换成大写
console.log(name.toUpperCase());

//获取指定的下标
console.log(name.indexOf('er'));
//获取子字符串 包括3不不包括8 [3,8)
console.log(name.substring(3, 8));


// 字符串匹配
// 规定要检索的字符串值。
stringObject.match(searchvalue)

// 或使用正则表达式
stringObject.match(regexp)

// trim() 方法会从一个字符串的两端删除空白字符。
// 在这个上下文中的空白字符是所有的空白字符(space, tab, no-break space 等)
// 以及所有行终止符字符(如 LF,CR等)
console.log(' hello world '.trim());

数组 Array

const arr = [1, 2, 3, 4, 5];
// 多维数组
let arr02 = [[1,2,3],[2,3],[1,2]];

// 长度
arr.length

// 通过元素获得下标索引
arr.indexOf('x')

// 截取数组的部分
arr.slice(3,7)
// 该方法向/从数组中添加/删除项目,然后返回被删除的项目。
// | 参数 | 描述 |
// | --------------- | --------------------------------------------------------------------- |
// | index | 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。 |
// | howmany | 必需。要删除的项目数量。如果设置为 0,则不会删除项目。 |
// | item1,...,itemX | 可选。向数组添加的新项目。 |
arrayObject.splice(index,howmany,item1,.....,itemX)
// 例删除第10个元素和第11个元素
array.splice(10,2)

// 就是在数组末尾添加元素,并返回新的长度
arr.push(3,7)
// 弹出最后一个元素
arr.pop()

// 方法可向数组的开头添加一个或更多元素,并返回新的长度
arr.unshift(1,2,3,4,5,7)
// 弹出第一个元素
arr.shift()

// sort排序
arr.sort();
//如果第一个自变量小于第二个自变量,则为负值;如果相等则为零;大于为正数
arr.sort((a,b)=>{
return a - b;
});

// 元素反转
arr.reverse()

// 数组拼接
// 注意,这个 concat 并没有改变原本的数组,而是返回一个拼接后的数组
let arr2 = arr.concat([1,2,3,4])

// join连接 使用特定的字符串连接
const arr = [1, 2, 3, 4, 5];
console.log(arr.join('-'));
// 输出-->
// 1-2-3-4-5

下面一些方法也经常用到

some() 方法用于检测数组中的元素是否满足指定条件;该方法会依次执行数组的每个元素;如果有一个元素满足条件,则表达式返回 true,剩余的元素不会再执行检测;如果没有满足条件的元素,则返回 false

// 检测数组中是否有元素大于 18。
var ages = [3, 10, 18, 20];

function myFunction() {
document.getElementById("demo").innerHTML = ages.some(function (age) {
return age >= 18;
});
}

filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。

var ages = [32, 33, 16, 40];

// 参数是一个回调函数,回调函数返回值是一个true

function myFunction() {
document.getElementById("demo").innerHTML = ages.filter(function(age) {
return age >= 18;
})
}

对象 Object

JavaScript 中的所有的键都是字符串,值是任意对象,所以可以这样取值 person['age']

使用一个不存在的对象属性不会报错而是会显示 undefined

var person = {
name:"alsritter",
age:3,
tags:['js','java','web','...']
}

// 动态的删减属性
delete person.name

// 动态的添加属性
person.sex = '男'

// 判断属性值是否在这个对象中
'age' in person
-->
true

//继承
'toString' in person
-->
true

//判断是否是自身的方法
person.hasOwnProperty('toString')
-->
false

Map 和 Set

这是 ES6 的新特性

// Map
let map = new Map([['tom',100],['jack',90],['jimmy',40]]);
map.set('lily',30);
console.log(map.get('tom'));
map.delete('tom');


// Set 无序不重复的集合
let set = new Set([1,2,3,4,5]);
set.add(6);
set.delete(4);
//判断是否存在某个元素
set.has(3);
-->
true

日期类型 Date

let now = new Date();
now.getFullYear();//年
now.getMonth();//星期
now.getDay();//星期几
now.getDate();//日
now.getHours();//时
now.getMinutes();//分
now.getSeconds();//秒

now.getTime();//获取时间戳(全世界统一)

//时间戳转成时间
let time = new Date(1590301998162);

//本地时间
console.log(now.toLocaleString());
console.log(now.toLocaleDateString());
-->
5/24/2020, 2:55:32 PM
5/24/2020

Json

在 JavaScript 中一切皆为对象,任何 JS 支持的格式都可以用 Json 来表示;

  • 对象都用 {}
  • 数组用 []
  • 所有的键值对都是用 key:value
let user = {
name:'alsritter',
age:20,
sex:'male'
}

//对象转换为json字符串
let str = JSON.stringify(user);
console.log(str);

//把对象转成对象
let o = JSON.parse(str);
console.log(o);

iterator 迭代器

of 关键字是 ES6 的特性,尽量使用这个,另一个 for in 有很多早期的 Bug;而遍历 Map,Set 只能用 iterator

let map = new Map([['tom',100],['jack',90],['jimmy',40]]);
for (let mapElement of map) {
console.log(mapElement);
}

let set = new Set([1,2,3,4,5]);
for (let number of set) {
console.log(number);
}

函数和方法

放在对象里叫做方法;放在外面叫做函数

一旦执行到 return 代表函数结束,返回结果;如果没有执行 return ,函数执行完也会返回结果,结果就是undefined

定义函数

最普通的方式

function abs(x) {
if (x>=0){
return x;
}else{
return -x;
}
}
console.log(abs(-10));
-->
10

以定义对象的形式定义函数,但是效果与上面那种是一样的;function (x){....} 是一个匿名函数,但是可以把结果返回给 abs,通过 abs 就可以调用

let abs = function (x) {
if (x>=0){
return x;
}else{
return -x;
}
}

console.log(abs(-10));

定义方法

"use strict";
// 唯一全局变量
const alsritter = {
name:'alsritter',
birth:2000,
//方法(因为是在对象的里面,所以叫做方法)
age:function () {
//方法 当前时间-birth
let now = new Date().getFullYear();
//注意这里也有this关键字
return now - this.birth;
}
}

//测试(调用方法一定要带括号)
console.log(alsritter.age());

尽量不要在这种写在外面的写法使用 this 关键字,因为 this 是结合上下文的动态更换的,如果在外部调用了这个方法则是使用的 window 对象

function getAge() {
//方法 当前时间-birth
let now = new Date().getFullYear();
//注意这里也有this关键字
return now - this.birth;
}

// 唯一全局变量
const alsritter = {
name:'alsritter',
birth:2000,
//注意这里不需要加括号
age:getAge // 这个方法可以用来计算年龄
}

//测试
console.log(alsritter.age());

而且 JS 有种创建 “Class” 的方式就是这样使用 this 作为构造函数调用,如下

let x = 100 // 这里定义一个全局对象为 100

function test() {
this.x = 1; // 这个 x 是构造方法里面的属性
}

let obj = new test();
console.log(obj.x); // 输出 1
console.log(x); // 输出 100

上文提到尽量不要在全局方法里使用 this 一般使用使用 apply 方法代替(apply 是所有函数/方法都有的方法);其作用是 改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象。因此,这时 this 指的就是这第一个参数。

function getAge() {
//方法 当前时间-birth
let now = new Date().getFullYear();
//注意这里也有this关键字
return now - this.birth;
}

//传入的第一个参数是 this 的对象,第二个是参数(但是不需要参数,所以这里为空)
console.log(getAge.apply(alsritter,[]));

可变长参数

以前实现多参数使用的是 arguments 关键字

if(arguments.length>2){
for(let i = 2;i<arguments.length;i++){
...
}
}

在 ES6 之后可以像 Java 一样使用 ... 来定义

let abs = function (...items) {
console.log(items);
}

abs(1,2,3,4,5,6);

-->
[ 1, 2, 3, 4, 5, 6 ]

返回一个数组(注意,这个items是自定义的变量名)

判断传入类型

使用关键字 typeof

let abs = function (x) {
//手动抛出异常
if(typeof x!== 'number'){
throw 'not a number!';
}

if (x>=0){
return x;
}else{
return -x;
}
}

console.log(abs('-10'));

// -->报错
// throw 'not a number!';
// ^
// not a number!
// (Use `node --trace-uncaught ...` to show where the exception was thrown)

传入多个参数的情况(使用关键字 arguments

let abs = function (x) {
if(arguments.length>1){
throw 'arguments oversized!';
}

if (x>=0){
return x;
}else{
return -x;
}
}

// console.log(abs(1,2));
//
// -->报错
// throw 'arguments oversized!';
// ^
// arguments oversized!
// (Use `node --trace-uncaught ...` to show where the exception was thrown)